import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:quick_dev_plugin/utils/log_util.dart';
import 'package:quick_dev_plugin/utils/toast_utils.dart';

import 'update_dialog.dart';

///author: create by SunJH
///时间: 2021/12/17 0017
///邮箱: 965989158@qq.com
///描述: 版本升级工具类

class UpDataVersionUtil {
  ///暂时代替从服务器获取的版本号
  var nowVersion = 10;
  var channel = const MethodChannel('quick_dev_plugin');

  static UpDataVersionUtil? _upDataVersionUtil;
  Dio? downloadDio;
  CancelToken cancelToken = CancelToken();
  var dstPath = "";
  var downloadProgress = 0.0.obs;
  var downloadResult = false;
  var _appName = "newApplication";

  UpdateDialog? dialog;

  static UpDataVersionUtil get instance =>
      _upDataVersionUtil ?? UpDataVersionUtil._();

  String get getAppName => _appName;

  UpDataVersionUtil._() {
    _upDataVersionUtil = this;
    downloadDio = Dio();
    ///处理证书验证失败问题
    (downloadDio!.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client){
      client.badCertificateCallback = (cert,host,port){
        return true;
      };
    };
  }

  Future<String?> printInfo(String info) =>channel.invokeMethod<String>("printInfo",{"info":info});

  ///检测版本是否需要升级
  ///context 更新提示弹窗显示必须要一个context
  ///versionName 版本名
  ///upDateLabel 版本更新说明
  ///isForce 是否强制，默认不强制
  ///applicationName 更新的软件名
  ///title 更新title
  upDateAppVersion(
  BuildContext context,
      String versionName,
      String applicationName,
      List<String> upDateLabel,
      String downloadPath,
     {bool isForce = false,
     String title = "版本更新"}) async {
    var explain = StringBuffer();
    upDateLabel.forEach((element){
      explain.write(element);
      explain.write("\n");
    });
    LogUtil.logI(explain.toString());
    dialog = UpdateDialog.showUpdate(context,
        title: title,
        isForce: isForce,
        updateContent:explain.toString(),
        onUpdate: ()async{
          await _doDownload(applicationName,versionName, downloadPath);
          LogUtil.logI("下载完毕，结果是:${downloadResult ? "成功" : "失败"}");
          if (!downloadResult) {
            ToastUtils.showTip("新版本下载失败");
            return;
          }
          var installApkResult = await installApk(dstPath);
          if (!installApkResult) {
            ToastUtils.showTip("安装失败");
            return;
          }
        });
    dialog?.show();
  }

  ///下载新版app isCanCancel 是否能取消下载
  Future<bool> _doDownload( var applicationName,String versionName,String downloadPath) async {
    var dir = await getExternalStorageDirectory();
    if (dir == null) return false;
    var appName = StringBuffer();
    appName.write(applicationName);
    appName.write("_");
    appName.write(versionName);
    appName.write(".apk");
    dstPath = path.join(dir.path, appName.toString());
    var file = File(dstPath);
    if (file.existsSync()){
      ///TODO 此处优化，应该检测确认安装包的完整性以及是否被篡改，再决定是否删除
      file.delete();
    }
    try {
      var response = await downloadDio?.download(downloadPath, dstPath,
        deleteOnError: false,
        onReceiveProgress: (count, total) {
        dialog?.update(count / total);
      },
          options: Options(receiveTimeout: 24 * 60 * 60 * 1000),
          cancelToken: cancelToken);
      downloadResult = (response?.statusCode ?? 0) == 200;
      LogUtil.logI("下载downloadResult:${response?.statusCode}");
      dialog?.dismiss();
      return downloadResult;
    } on DioError catch(e) {
      e.printInfo();
      e.printError();
      LogUtil.logI("下载出错");
      dialog?.dismiss();
      return downloadResult;
    }
  }

  ///安装新版本的apk
  Future<bool> installApk(String dstPath) async {
    LogUtil.logI("进行新版本安装:$dstPath");
    var invokeMethod =
        await channel.invokeMethod("installApp", {"appFilePath": dstPath});
    if (invokeMethod != null && invokeMethod is bool) {
      if (invokeMethod) {
        ToastUtils.showTip("安装成功");
        return true;
      }
    }
    return false;
  }

}
